{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### RNN with my own pre-trained vectors (by CBOW)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "%load_ext autoreload\n",
    "%autoreload 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/ellfae/anaconda3/envs/tensorflow/lib/python3.6/site-packages/h5py/__init__.py:36: FutureWarning: Conversion of the second argument of issubdtype from `float` to `np.floating` is deprecated. In future, it will be treated as `np.float64 == np.dtype(float).type`.\n",
      "  from ._conv import register_converters as _register_converters\n",
      "Using TensorFlow backend.\n",
      "/home/ellfae/anaconda3/envs/tensorflow/lib/python3.6/site-packages/sklearn/cross_validation.py:44: DeprecationWarning: This module was deprecated in version 0.18 in favor of the model_selection module into which all the refactored classes and functions are moved. Also note that the interface of the new CV iterators are different from that of this module. This module will be removed in 0.20.\n",
      "  \"This module will be removed in 0.20.\", DeprecationWarning)\n"
     ]
    }
   ],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "from sklearn import preprocessing, metrics, decomposition, pipeline, dummy\n",
    "from nltk.tokenize import TweetTokenizer\n",
    "\n",
    "import tensorflow as tf\n",
    "from tensorflow.contrib.rnn import GRUCell\n",
    "from tensorflow.python.ops.rnn import dynamic_rnn as rnn\n",
    "from tensorflow.python.ops.rnn import bidirectional_dynamic_rnn as bi_rnn\n",
    "\n",
    "from keras.datasets import imdb\n",
    "import os\n",
    "import helpers.preprocessing as prep\n",
    "import helpers.regprep as regprep\n",
    "# to perform evaluations (new one - mines)\n",
    "import helpers.evaluate as ev\n",
    "evaluator = ev.Evaluate()\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "import helpers.pickle_helpers as ph\n",
    "import gensim\n",
    "from gensim.models import KeyedVectors\n",
    "import time\n",
    "import math\n",
    "#os.environ['CUDA_VISIBLE_DEVICES'] = ''\n",
    "from sklearn.cross_validation import train_test_split\n",
    "import re"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Parameters"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "NUM_WORDS = 10000 # max size of vocabulary\n",
    "EMBEDDING_DIM = 128\n",
    "HIDDEN_SIZE = 256\n",
    "ATTENTION_SIZE = 150\n",
    "KEEP_PROB = 0.8\n",
    "BATCH_SIZE = 128\n",
    "NUM_EPOCHS = 50 # Model easily overfits without pre-trained words embeddings, that's why train for a few epochs\n",
    "DELTA = 0.5\n",
    "NUM_LAYERS = 3\n",
    "LEARNING_RATE = 0.0001"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Data Preparation\n",
    "- Preprocess using Husein helpers"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "train_data = ph.load_from_pickle(directory=\"data/husein_emotion/emotion-english/merged_training.pkl\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "### TODO: move this preprocessing helper functions\n",
    "def clearstring(string):\n",
    "    string = re.sub('[^\\'\\\"A-Za-z0-9 ]+', '', string)\n",
    "    string = string.split(' ')\n",
    "    string = filter(None, string)\n",
    "    string = [y.strip() for y in string]\n",
    "    string = [y for y in string if len(y) > 3 and y.find('nbsp') < 0]\n",
    "    return ' '.join(string)\n",
    "\n",
    "def read_data_with_pandas():\n",
    "    \"\"\" I already converted the data into pandas to we can avoid the function above\"\"\"\n",
    "    vocab = []\n",
    "    text = train_data.text.values.tolist()\n",
    "    for t in text:\n",
    "        strings = clearstring(t)\n",
    "        vocab+=strings.split()\n",
    "    return vocab"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "train_data.text = train_data.text.apply(lambda d: clearstring(d))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "### split and sample\n",
    "train_data, test_data, val_data = prep.split_original(train_data, 20)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "### Sampling\n",
    "#train_data = train_data.sample(n=10000, random_state=10).copy()\n",
    "#test_data = test_data.sample(n=10000, random_state=10).copy()\n",
    "#val_data = val_data.sample(n=10000, random_state=10).copy()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Obtain word embeddings"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "### load word embeddings and accompanyig vocabulary\n",
    "wv = ph.load_from_pickle(\"data/husein_emotion/tf_embeddings/tf_cbow_embeddings.p\")\n",
    "vocab = ph.load_from_pickle(\"data/husein_emotion/tf_embeddings/tf_cbow_dictionary.p\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(128,)"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "### eg. to obtain embedding for token\n",
    "wv[vocab[\"feel\"]].shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Tokenization and Label Binarization"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "def remove_unknown_words(tokens):\n",
    "    return [t for t in tokens if t in vocab]\n",
    "\n",
    "def check_size(c, size):\n",
    "    if len(c) <= size:\n",
    "        return False\n",
    "    else:\n",
    "        return True\n",
    "    \n",
    "### tokens and tokensize\n",
    "train_data[\"tokens\"] = train_data.text.apply(lambda t: remove_unknown_words(t.split()))\n",
    "train_data[\"tokensize\"] = train_data.tokens.apply(lambda t: len(t))\n",
    "test_data[\"tokens\"] = test_data.text.apply(lambda t: remove_unknown_words(t.split()))\n",
    "test_data[\"tokensize\"] = test_data.tokens.apply(lambda t: len(t))\n",
    "val_data[\"tokens\"] = val_data.text.apply(lambda t: remove_unknown_words(t.split()))\n",
    "val_data[\"tokensize\"] = val_data.tokens.apply(lambda t: len(t))\n",
    "\n",
    "\n",
    "### filter by tokensize\n",
    "train_data = train_data.loc[train_data[\"tokens\"].apply(lambda d: check_size(d, 7)) != False].copy()\n",
    "test_data = test_data.loc[test_data[\"tokens\"].apply(lambda d: check_size(d, 7)) != False].copy()\n",
    "val_data = val_data.loc[val_data[\"tokens\"].apply(lambda d: check_size(d, 7)) != False].copy()\n",
    "\n",
    "### sorting by tokensize\n",
    "train_data.sort_values(by=\"tokensize\", ascending=True, inplace=True)\n",
    "test_data.sort_values(by=\"tokensize\", ascending=True, inplace=True)\n",
    "val_data.sort_values(by=\"tokensize\", ascending=True, inplace=True)\n",
    "\n",
    "### resetting index\n",
    "train_data.reset_index(drop=True, inplace=True);\n",
    "test_data.reset_index(drop=True, inplace=True);\n",
    "val_data.reset_index(drop=True, inplace=True);\n",
    "\n",
    "### Binarization\n",
    "emotions = list(set(train_data.emotions.unique()))\n",
    "num_emotions = len(emotions)\n",
    "\n",
    "# binarizer\n",
    "mlb = preprocessing.MultiLabelBinarizer()\n",
    "\n",
    "train_data_labels =  [set(emos) & set(emotions) for emos in train_data[['emotions']].values]\n",
    "test_data_labels =  [set(emos) & set(emotions) for emos in test_data[['emotions']].values]\n",
    "val_data_labels =  [set(emos) & set(emotions) for emos in val_data[['emotions']].values]\n",
    "\n",
    "y_bin_emotions = mlb.fit_transform(train_data_labels)\n",
    "test_y_bin_emotions = mlb.fit_transform(test_data_labels)\n",
    "val_y_bin_emotions = mlb.fit_transform(val_data_labels)\n",
    "\n",
    "train_data['bin_emotions'] = y_bin_emotions.tolist()\n",
    "test_data['bin_emotions'] = test_y_bin_emotions.tolist()\n",
    "val_data['bin_emotions'] = val_y_bin_emotions.tolist()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Batching by Bucketing approach"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "### renders embeddings with paddings; zeros where missing tokens\n",
    "def generate_embeds_with_pads(tokens, max_size):\n",
    "   \n",
    "    padded_embedding = []\n",
    "    for i in range(max_size):\n",
    "        if i+1 > len(tokens): # do padding\n",
    "            padded_embedding.append(list(np.zeros(EMBEDDING_DIM)))\n",
    "        else: # do embedding for existing tokens\n",
    "            padded_embedding.append(list(wv[vocab[tokens[i]]]))  \n",
    "    return padded_embedding\n",
    "\n",
    "### generate the actual batches\n",
    "def generate_batches(data, batch_size):\n",
    "    actual_batches = math.ceil(len(data) / batch_size)\n",
    "    bins = np.linspace(0, len(data), actual_batches + 1) # this renders actual batches bins of size batch_size\n",
    "    groups = data.groupby(np.digitize(data.index, bins))\n",
    "    \n",
    "    groups_indices = groups.indices\n",
    "    groups_maxes = groups.max().tokensize\n",
    "    \n",
    "    return groups.indices, groups_maxes"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "class EmoNet:    \n",
    "    def __init__(self, num_layers, size_layer, dimension_input, dimension_output, learning_rate):\n",
    "        def lstm_cell():\n",
    "            return tf.nn.rnn_cell.LSTMCell(size_layer)\n",
    "        ### input\n",
    "        self.rnn_cells = tf.nn.rnn_cell.MultiRNNCell([lstm_cell() for _ in range(num_layers)])\n",
    "        self.X = tf.placeholder(tf.float32, [None, None, dimension_input])\n",
    "        self.Y = tf.placeholder(tf.float32, [None, dimension_output])\n",
    "        drop = tf.contrib.rnn.DropoutWrapper(self.rnn_cells, output_keep_prob = 0.5)\n",
    "        \n",
    "        ### forward\n",
    "        self.outputs, self.last_state = tf.nn.dynamic_rnn(drop, self.X, dtype = tf.float32)\n",
    "        self.rnn_W = tf.Variable(tf.random_normal((size_layer, dimension_output)))\n",
    "        self.rnn_B = tf.Variable(tf.random_normal([dimension_output]))\n",
    "        \n",
    "        ### loss, optimization, accuracy\n",
    "        self.logits = tf.matmul(self.outputs[:, -1], self.rnn_W) + self.rnn_B\n",
    "        self.cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits = self.logits, labels = self.Y))\n",
    "        l2 = sum(0.0005 * tf.nn.l2_loss(tf_var) for tf_var in tf.trainable_variables())\n",
    "        self.cost += l2\n",
    "        self.optimizer = tf.train.AdamOptimizer(learning_rate = learning_rate).minimize(self.cost)\n",
    "        self.correct_pred = tf.equal(tf.argmax(self.logits, 1), tf.argmax(self.Y, 1))\n",
    "        self.accuracy = tf.reduce_mean(tf.cast(self.correct_pred, tf.float32))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Training"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "### define model\n",
    "tf.reset_default_graph()\n",
    "sess = tf.InteractiveSession()\n",
    "model = EmoNet(NUM_LAYERS, HIDDEN_SIZE, EMBEDDING_DIM, num_emotions, LEARNING_RATE)\n",
    "sess.run(tf.global_variables_initializer())\n",
    "dimension = EMBEDDING_DIM\n",
    "saver = tf.train.Saver(tf.global_variables())\n",
    "EARLY_STOPPING, CURRENT_CHECKPOINT, CURRENT_ACC, EPOCH = 10, 0, 0, 0\n",
    "\n",
    "### defining batch generation\n",
    "train_groups_indices, train_groups_maxes = generate_batches(train_data, BATCH_SIZE)\n",
    "test_groups_indices, test_groups_maxes = generate_batches(test_data, BATCH_SIZE)\n",
    "val_groups_indices, val_groups_maxes = generate_batches(val_data, BATCH_SIZE)\n",
    "\n",
    "n_train = len(train_data) // BATCH_SIZE\n",
    "n_test = len(test_data) // BATCH_SIZE\n",
    "n_val = len(val_data) // BATCH_SIZE"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "epoch: 0 , pass acc: 0 , current acc: 0.44793318906455365\n",
      "time taken: 120.65529823303223\n",
      "epoch: 1 , training loss: 1.8497494605181795 , training acc: 0.48508491165136264 , valid loss: 1.8182489947207923 , valid acc: 0.44793318906455365\n",
      "epoch: 1 , pass acc: 0.44793318906455365 , current acc: 0.4703425406252296\n",
      "time taken: 121.70198845863342\n",
      "epoch: 2 , training loss: 1.660787812719351 , training acc: 0.5180269489691719 , valid loss: 1.7152376516351422 , valid acc: 0.4703425406252296\n",
      "epoch: 2 , pass acc: 0.4703425406252296 , current acc: 0.5126047536586095\n",
      "time taken: 121.93270444869995\n",
      "epoch: 3 , training loss: 1.5584344023860102 , training acc: 0.546390782058998 , valid loss: 1.5831360064663933 , valid acc: 0.5126047536586095\n",
      "epoch: 3 , pass acc: 0.5126047536586095 , current acc: 0.5833902684519592\n",
      "time taken: 121.7117645740509\n",
      "epoch: 4 , training loss: 1.4278881854906886 , training acc: 0.5927821245245531 , valid loss: 1.4361504096429325 , valid acc: 0.5833902684519592\n",
      "epoch: 4 , pass acc: 0.5833902684519592 , current acc: 0.6118284617234202\n",
      "time taken: 121.86613655090332\n",
      "epoch: 5 , training loss: 1.3232281770469059 , training acc: 0.6304229356940404 , valid loss: 1.3620667336056533 , valid acc: 0.6118284617234202\n",
      "time taken: 121.7077534198761\n",
      "epoch: 6 , training loss: 1.2355186933456153 , training acc: 0.6605543490971414 , valid loss: 1.3279613713616307 , valid acc: 0.6094460689905777\n",
      "epoch: 6 , pass acc: 0.6118284617234202 , current acc: 0.6493889044210749\n",
      "time taken: 121.70735216140747\n",
      "epoch: 7 , training loss: 1.1624995414743717 , training acc: 0.6852692428178828 , valid loss: 1.2342415023775934 , valid acc: 0.6493889044210749\n",
      "time taken: 121.9378182888031\n",
      "epoch: 8 , training loss: 1.1014408246541183 , training acc: 0.7058657894646347 , valid loss: 1.2190264194335751 , valid acc: 0.6486707216906316\n",
      "time taken: 121.7919750213623\n",
      "epoch: 9 , training loss: 1.04911506877226 , training acc: 0.7242000939052274 , valid loss: 1.206145175741714 , valid acc: 0.6479068514212821\n",
      "epoch: 9 , pass acc: 0.6493889044210749 , current acc: 0.6542402879127021\n",
      "time taken: 121.84319186210632\n",
      "epoch: 10 , training loss: 1.0044245269169874 , training acc: 0.7402570842973676 , valid loss: 1.1960572571430392 , valid acc: 0.6542402879127021\n",
      "epoch: 10 , pass acc: 0.6542402879127021 , current acc: 0.6643151316827941\n",
      "time taken: 122.2366189956665\n",
      "epoch: 11 , training loss: 0.9655496181322634 , training acc: 0.7543657525443106 , valid loss: 1.1766827641760262 , valid acc: 0.6643151316827941\n",
      "epoch: 11 , pass acc: 0.6643151316827941 , current acc: 0.697535726630572\n",
      "time taken: 122.02811789512634\n",
      "epoch: 12 , training loss: 0.9302466137615965 , training acc: 0.767625772280719 , valid loss: 1.0988975740173488 , valid acc: 0.697535726630572\n",
      "epoch: 12 , pass acc: 0.697535726630572 , current acc: 0.7174315912630952\n",
      "time taken: 121.93449449539185\n",
      "epoch: 13 , training loss: 0.8993743757828573 , training acc: 0.7786525726462943 , valid loss: 1.050530862750359 , valid acc: 0.7174315912630952\n",
      "epoch: 13 , pass acc: 0.7174315912630952 , current acc: 0.75062441362918\n",
      "time taken: 122.25388288497925\n",
      "epoch: 14 , training loss: 0.870630697382805 , training acc: 0.7892790170349158 , valid loss: 0.9734162997852251 , valid acc: 0.75062441362918\n",
      "epoch: 14 , pass acc: 0.75062441362918 , current acc: 0.7576530358745056\n",
      "time taken: 121.87480998039246\n",
      "epoch: 15 , training loss: 0.845692293220321 , training acc: 0.7978096733749672 , valid loss: 0.9637964223195048 , valid acc: 0.7576530358745056\n",
      "epoch: 15 , pass acc: 0.7576530358745056 , current acc: 0.7722654145898171\n",
      "time taken: 122.18748617172241\n",
      "epoch: 16 , training loss: 0.8243039162177762 , training acc: 0.8056006484352654 , valid loss: 0.9275312689901556 , valid acc: 0.7722654145898171\n",
      "epoch: 16 , pass acc: 0.7722654145898171 , current acc: 0.7816815040643933\n",
      "time taken: 122.278076171875\n",
      "epoch: 17 , training loss: 0.8022008860306424 , training acc: 0.8137915690354393 , valid loss: 0.908306437209972 , valid acc: 0.7816815040643933\n",
      "epoch: 17 , pass acc: 0.7816815040643933 , current acc: 0.7957405395878171\n",
      "time taken: 122.05603361129761\n",
      "epoch: 18 , training loss: 0.7850586705817968 , training acc: 0.8199235959585107 , valid loss: 0.8818140695395978 , valid acc: 0.7957405395878171\n",
      "epoch: 18 , pass acc: 0.7957405395878171 , current acc: 0.8045122067905167\n",
      "time taken: 121.9764051437378\n",
      "epoch: 19 , training loss: 0.7670767968029163 , training acc: 0.8266257911179555 , valid loss: 0.8615349583255435 , valid acc: 0.8045122067905167\n",
      "epoch: 19 , pass acc: 0.8045122067905167 , current acc: 0.8100202558110061\n",
      "time taken: 122.29010701179504\n",
      "epoch: 20 , training loss: 0.7501278550354475 , training acc: 0.8322033929853746 , valid loss: 0.8407506612898077 , valid acc: 0.8100202558110061\n",
      "time taken: 121.8595860004425\n",
      "epoch: 21 , training loss: 0.7344990358560862 , training acc: 0.837396679899055 , valid loss: 0.8536818979434597 , valid acc: 0.8051596153708338\n",
      "epoch: 21 , pass acc: 0.8100202558110061 , current acc: 0.8150690267386945\n",
      "time taken: 121.963223695755\n",
      "epoch: 22 , training loss: 0.7200973649831741 , training acc: 0.8416198909174246 , valid loss: 0.8241352381058109 , valid acc: 0.8150690267386945\n",
      "time taken: 121.84305667877197\n",
      "epoch: 23 , training loss: 0.7053801936044919 , training acc: 0.8468946522116444 , valid loss: 0.8207435020543996 , valid acc: 0.8140405786847605\n",
      "epoch: 23 , pass acc: 0.8150690267386945 , current acc: 0.8259982255477349\n",
      "time taken: 121.75306725502014\n",
      "epoch: 24 , training loss: 0.6917140633681097 , training acc: 0.8515626115102056 , valid loss: 0.7938945345508243 , valid acc: 0.8259982255477349\n",
      "time taken: 121.67529630661011\n",
      "epoch: 25 , training loss: 0.6796895203950406 , training acc: 0.8551347407881168 , valid loss: 0.7978769760687374 , valid acc: 0.8205385529300542\n",
      "epoch: 25 , pass acc: 0.8259982255477349 , current acc: 0.8266868435063408\n",
      "time taken: 121.78309488296509\n",
      "epoch: 26 , training loss: 0.66638015515158 , training acc: 0.8591213266801805 , valid loss: 0.7880739155903603 , valid acc: 0.8266868435063408\n",
      "epoch: 26 , pass acc: 0.8266868435063408 , current acc: 0.8304470682028428\n",
      "time taken: 121.88212561607361\n",
      "epoch: 27 , training loss: 0.6549240136739338 , training acc: 0.8623580847312784 , valid loss: 0.7881488539640186 , valid acc: 0.8304470682028428\n",
      "epoch: 27 , pass acc: 0.8304470682028428 , current acc: 0.8318947785108992\n",
      "time taken: 122.29499983787537\n",
      "epoch: 28 , training loss: 0.6436379243020508 , training acc: 0.8660977128927024 , valid loss: 0.774020403334238 , valid acc: 0.8318947785108992\n",
      "epoch: 28 , pass acc: 0.8318947785108992 , current acc: 0.8352339487631344\n",
      "time taken: 121.88087248802185\n",
      "epoch: 29 , training loss: 0.6329335377496832 , training acc: 0.8689128882672441 , valid loss: 0.7568110187076827 , valid acc: 0.8352339487631344\n",
      "epoch: 29 , pass acc: 0.8352339487631344 , current acc: 0.840063831759888\n",
      "time taken: 122.10181641578674\n",
      "epoch: 30 , training loss: 0.6246843818572885 , training acc: 0.8711728553760406 , valid loss: 0.7377681682989435 , valid acc: 0.840063831759888\n",
      "epoch: 30 , pass acc: 0.840063831759888 , current acc: 0.8454927475128359\n",
      "time taken: 122.22630167007446\n",
      "epoch: 31 , training loss: 0.6147076672246921 , training acc: 0.8735611514657682 , valid loss: 0.7106234908682628 , valid acc: 0.8454927475128359\n",
      "epoch: 31 , pass acc: 0.8454927475128359 , current acc: 0.8509580938561448\n",
      "time taken: 121.98713827133179\n",
      "epoch: 32 , training loss: 0.6059981906247761 , training acc: 0.875842232860313 , valid loss: 0.6955613492472658 , valid acc: 0.8509580938561448\n",
      "epoch: 32 , pass acc: 0.8509580938561448 , current acc: 0.8511459240056936\n",
      "time taken: 121.87098383903503\n",
      "epoch: 33 , training loss: 0.5975064512561349 , training acc: 0.8783055111955628 , valid loss: 0.6920928787259222 , valid acc: 0.8511459240056936\n",
      "epoch: 33 , pass acc: 0.8511459240056936 , current acc: 0.8525127091454071\n",
      "time taken: 121.98001146316528\n",
      "epoch: 34 , training loss: 0.5893720580347384 , training acc: 0.8804140577466651 , valid loss: 0.6753445548339955 , valid acc: 0.8525127091454071\n",
      "epoch: 34 , pass acc: 0.8525127091454071 , current acc: 0.8531230876168001\n",
      "time taken: 122.09599375724792\n",
      "epoch: 35 , training loss: 0.5829017689872902 , training acc: 0.8818268684490729 , valid loss: 0.6707351303216323 , valid acc: 0.8531230876168001\n",
      "epoch: 35 , pass acc: 0.8531230876168001 , current acc: 0.8535760950694964\n",
      "time taken: 121.87074089050293\n",
      "epoch: 36 , training loss: 0.5757910250677637 , training acc: 0.8845468794236839 , valid loss: 0.6660597981179802 , valid acc: 0.8535760950694964\n",
      "epoch: 36 , pass acc: 0.8535760950694964 , current acc: 0.8566178401697029\n",
      "time taken: 122.33615350723267\n",
      "epoch: 37 , training loss: 0.5684821470315851 , training acc: 0.8857266087471318 , valid loss: 0.6512178623849906 , valid acc: 0.8566178401697029\n",
      "time taken: 121.86045813560486\n",
      "epoch: 38 , training loss: 0.562928714034339 , training acc: 0.8875188099897002 , valid loss: 0.6483464411740164 , valid acc: 0.8555478847142562\n",
      "time taken: 121.78364181518555\n",
      "epoch: 39 , training loss: 0.5553115934332332 , training acc: 0.889343242633697 , valid loss: 0.6489480281049765 , valid acc: 0.8535820691330919\n",
      "time taken: 122.14467191696167\n",
      "epoch: 40 , training loss: 0.5508782191483305 , training acc: 0.890386100933001 , valid loss: 0.6377879980119686 , valid acc: 0.856348783935158\n",
      "time taken: 121.77689409255981\n",
      "epoch: 41 , training loss: 0.5451024591995052 , training acc: 0.8917260543008947 , valid loss: 0.6513471282222896 , valid acc: 0.8521710862812487\n",
      "epoch: 41 , pass acc: 0.8566178401697029 , current acc: 0.8594977349332236\n",
      "time taken: 122.05215096473694\n",
      "epoch: 42 , training loss: 0.5389942612663915 , training acc: 0.8931920244304826 , valid loss: 0.6301748338833596 , valid acc: 0.8594977349332236\n",
      "epoch: 42 , pass acc: 0.8594977349332236 , current acc: 0.8631032742921588\n",
      "time taken: 122.01391768455505\n",
      "epoch: 43 , training loss: 0.5352470322295779 , training acc: 0.8940633545144534 , valid loss: 0.6190859316622169 , valid acc: 0.8631032742921588\n",
      "time taken: 121.83848595619202\n",
      "epoch: 44 , training loss: 0.5297746505970085 , training acc: 0.8950879330559888 , valid loss: 0.6302624278276869 , valid acc: 0.8569519950926883\n",
      "time taken: 121.94421339035034\n",
      "epoch: 45 , training loss: 0.5244319901783008 , training acc: 0.8964573582278518 , valid loss: 0.6260409224959254 , valid acc: 0.8583599910574052\n",
      "time taken: 122.21364665031433\n",
      "epoch: 46 , training loss: 0.5203626014522671 , training acc: 0.8971018375159033 , valid loss: 0.6119646603621326 , valid acc: 0.8630333971051336\n",
      "epoch: 46 , pass acc: 0.8631032742921588 , current acc: 0.8651903312183121\n",
      "time taken: 122.07616949081421\n",
      "epoch: 47 , training loss: 0.5164706225898354 , training acc: 0.8981244759605899 , valid loss: 0.6111171012653888 , valid acc: 0.8651903312183121\n",
      "time taken: 121.9002799987793\n",
      "epoch: 48 , training loss: 0.5115507135360873 , training acc: 0.898551803274253 , valid loss: 0.6121598829343481 , valid acc: 0.8631038703386066\n",
      "time taken: 121.96682405471802\n",
      "epoch: 49 , training loss: 0.5084455485341042 , training acc: 0.8994946468230665 , valid loss: 0.6336311015110572 , valid acc: 0.8588118026557477\n",
      "epoch: 49 , pass acc: 0.8651903312183121 , current acc: 0.8768484621372038\n",
      "time taken: 122.15149998664856\n",
      "epoch: 50 , training loss: 0.5046615014118162 , training acc: 0.9006697505875166 , valid loss: 0.5715025096263701 , valid acc: 0.8768484621372038\n",
      "epoch: 50 , pass acc: 0.8768484621372038 , current acc: 0.8782567538104011\n",
      "time taken: 122.02922368049622\n",
      "epoch: 51 , training loss: 0.5006748779822003 , training acc: 0.9013437752365127 , valid loss: 0.5644247335137673 , valid acc: 0.8782567538104011\n",
      "epoch: 51 , pass acc: 0.8782567538104011 , current acc: 0.8822421379459714\n",
      "time taken: 122.25015592575073\n",
      "epoch: 52 , training loss: 0.4974519267380057 , training acc: 0.9018942089497212 , valid loss: 0.5518295780836957 , valid acc: 0.8822421379459714\n",
      "time taken: 121.92034316062927\n",
      "epoch: 53 , training loss: 0.49418100712876234 , training acc: 0.9020768907158356 , valid loss: 0.5844524355189314 , valid acc: 0.8737350470811418\n",
      "epoch: 53 , pass acc: 0.8822421379459714 , current acc: 0.8863511505057511\n",
      "time taken: 122.09381771087646\n",
      "epoch: 54 , training loss: 0.4915648533077656 , training acc: 0.9029118859312475 , valid loss: 0.5464737927450717 , valid acc: 0.8863511505057511\n",
      "epoch: 54 , pass acc: 0.8863511505057511 , current acc: 0.8875271171620749\n",
      "time taken: 122.31992745399475\n",
      "epoch: 55 , training loss: 0.48727335262616667 , training acc: 0.904006373817231 , valid loss: 0.5453208776064289 , valid acc: 0.8875271171620749\n",
      "time taken: 121.99750876426697\n",
      "epoch: 56 , training loss: 0.48485981944548573 , training acc: 0.9046752131151531 , valid loss: 0.5538591058219521 , valid acc: 0.8846391624617345\n",
      "epoch: 56 , pass acc: 0.8875271171620749 , current acc: 0.8885062918500993\n",
      "time taken: 121.99553084373474\n",
      "epoch: 57 , training loss: 0.4821504374537922 , training acc: 0.9049214254082009 , valid loss: 0.5316389473607239 , valid acc: 0.8885062918500993\n",
      "time taken: 121.8370156288147\n",
      "epoch: 58 , training loss: 0.48043210501740236 , training acc: 0.9049079953865111 , valid loss: 0.5480772129540304 , valid acc: 0.8866515622555631\n",
      "time taken: 121.82136106491089\n",
      "epoch: 59 , training loss: 0.4769056755134451 , training acc: 0.9056046269675904 , valid loss: 0.5447702419410632 , valid acc: 0.8869558558302019\n",
      "time taken: 121.91621041297913\n",
      "epoch: 60 , training loss: 0.47519019739493373 , training acc: 0.9055954125377176 , valid loss: 0.541284955820991 , valid acc: 0.8861573462926068\n",
      "epoch: 60 , pass acc: 0.8885062918500993 , current acc: 0.8918153033094499\n",
      "time taken: 122.02556729316711\n",
      "epoch: 61 , training loss: 0.4718389834795235 , training acc: 0.9065816042060343 , valid loss: 0.5178580618309743 , valid acc: 0.8918153033094499\n",
      "time taken: 122.2250382900238\n",
      "epoch: 62 , training loss: 0.46978297422986237 , training acc: 0.906889369554271 , valid loss: 0.5252661852581987 , valid acc: 0.8895386225968889\n",
      "epoch: 62 , pass acc: 0.8918153033094499 , current acc: 0.8949290166780787\n",
      "time taken: 122.06269836425781\n",
      "epoch: 63 , training loss: 0.4671113013932024 , training acc: 0.9067181031439361 , valid loss: 0.5021016871176877 , valid acc: 0.8949290166780787\n",
      "time taken: 121.98753666877747\n",
      "epoch: 64 , training loss: 0.4650797129870184 , training acc: 0.9076519932726645 , valid loss: 0.5238961791529239 , valid acc: 0.8891223475192357\n",
      "time taken: 121.76196670532227\n",
      "epoch: 65 , training loss: 0.46183970245250866 , training acc: 0.9075720489495013 , valid loss: 0.513489637126043 , valid acc: 0.8905228752534367\n",
      "time taken: 121.88672161102295\n",
      "epoch: 66 , training loss: 0.45896521105847266 , training acc: 0.9081784024825597 , valid loss: 0.515331454792069 , valid acc: 0.8909785683872631\n",
      "time taken: 122.3310067653656\n",
      "epoch: 67 , training loss: 0.4580339447269301 , training acc: 0.9085337315421165 , valid loss: 0.5089274041571663 , valid acc: 0.8900701678493648\n",
      "epoch: 67 , pass acc: 0.8949290166780787 , current acc: 0.8971632918686543\n",
      "time taken: 122.04922819137573\n",
      "epoch: 68 , training loss: 0.4544926493402103 , training acc: 0.9086766838304486 , valid loss: 0.4819681939569492 , valid acc: 0.8971632918686543\n"
     ]
    },
    {
     "ename": "KeyboardInterrupt",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mKeyboardInterrupt\u001b[0m                         Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-15-50a48767207f>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m     13\u001b[0m         \u001b[0mbatch_y\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtrain_data\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mloc\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mtrain_groups_indices\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mb\u001b[0m\u001b[0;34m+\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mbin_emotions\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvalues\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtolist\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     14\u001b[0m         \u001b[0;31m#print(batch_x)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 15\u001b[0;31m         \u001b[0mloss\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0m_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0msess\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrun\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mmodel\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcost\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmodel\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0moptimizer\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfeed_dict\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0mmodel\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mX\u001b[0m \u001b[0;34m:\u001b[0m \u001b[0mbatch_x\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmodel\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mY\u001b[0m \u001b[0;34m:\u001b[0m \u001b[0mbatch_y\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     16\u001b[0m         \u001b[0mtrain_loss\u001b[0m \u001b[0;34m+=\u001b[0m \u001b[0mloss\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     17\u001b[0m         \u001b[0mtrain_acc\u001b[0m \u001b[0;34m+=\u001b[0m \u001b[0msess\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrun\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmodel\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0maccuracy\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfeed_dict\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0mmodel\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mX\u001b[0m \u001b[0;34m:\u001b[0m \u001b[0mbatch_x\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmodel\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mY\u001b[0m \u001b[0;34m:\u001b[0m \u001b[0mbatch_y\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/anaconda3/envs/tensorflow/lib/python3.6/site-packages/tensorflow/python/client/session.py\u001b[0m in \u001b[0;36mrun\u001b[0;34m(self, fetches, feed_dict, options, run_metadata)\u001b[0m\n\u001b[1;32m    787\u001b[0m     \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    788\u001b[0m       result = self._run(None, fetches, feed_dict, options_ptr,\n\u001b[0;32m--> 789\u001b[0;31m                          run_metadata_ptr)\n\u001b[0m\u001b[1;32m    790\u001b[0m       \u001b[0;32mif\u001b[0m \u001b[0mrun_metadata\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    791\u001b[0m         \u001b[0mproto_data\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtf_session\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mTF_GetBuffer\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mrun_metadata_ptr\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/anaconda3/envs/tensorflow/lib/python3.6/site-packages/tensorflow/python/client/session.py\u001b[0m in \u001b[0;36m_run\u001b[0;34m(self, handle, fetches, feed_dict, options, run_metadata)\u001b[0m\n\u001b[1;32m    966\u001b[0m             \u001b[0mfeed_handles\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0msubfeed_name\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0msubfeed_val\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    967\u001b[0m           \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 968\u001b[0;31m             \u001b[0mnp_val\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0masarray\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msubfeed_val\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0msubfeed_dtype\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    969\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    970\u001b[0m           if (not is_tensor_handle_feed and\n",
      "\u001b[0;32m~/anaconda3/envs/tensorflow/lib/python3.6/site-packages/numpy/core/numeric.py\u001b[0m in \u001b[0;36masarray\u001b[0;34m(a, dtype, order)\u001b[0m\n\u001b[1;32m    490\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    491\u001b[0m     \"\"\"\n\u001b[0;32m--> 492\u001b[0;31m     \u001b[0;32mreturn\u001b[0m \u001b[0marray\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ma\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcopy\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mFalse\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0morder\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0morder\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    493\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    494\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mKeyboardInterrupt\u001b[0m: "
     ]
    }
   ],
   "source": [
    "### training\n",
    "while True:\n",
    "    lasttime = time.time()\n",
    "    ### early stoping to avoid overfitting\n",
    "    if CURRENT_CHECKPOINT == EARLY_STOPPING:\n",
    "        print('break epoch:', EPOCH)\n",
    "        break\n",
    "    train_acc, train_loss, val_acc , val_loss = 0, 0, 0, 0\n",
    "    \n",
    "    for b in range(n_train):\n",
    "        batch_x = train_data.iloc[train_groups_indices[b+1]].tokens.apply(lambda d: \n",
    "                                                                          generate_embeds_with_pads(d, train_groups_maxes[b+1]) ).values.tolist()\n",
    "        batch_y = train_data.loc[train_groups_indices[b+1]].bin_emotions.values.tolist()\n",
    "        #print(batch_x)\n",
    "        loss, _ = sess.run([model.cost, model.optimizer], feed_dict = {model.X : batch_x, model.Y : batch_y})\n",
    "        train_loss += loss\n",
    "        train_acc += sess.run(model.accuracy, feed_dict = {model.X : batch_x, model.Y : batch_y})\n",
    "    \n",
    "    for b in range(n_val):\n",
    "        batch_x = val_data.iloc[val_groups_indices[b+1]].tokens.apply(lambda d: \n",
    "                                                                          generate_embeds_with_pads(d, val_groups_maxes[b+1]) ).values.tolist()\n",
    "        batch_y = val_data.loc[val_groups_indices[b+1]].bin_emotions.values.tolist()\n",
    "        loss, acc = sess.run([model.cost, model.accuracy], feed_dict = {model.X : batch_x, model.Y : batch_y})\n",
    "        val_loss += loss\n",
    "        val_acc += acc\n",
    "    \n",
    "    train_loss /= n_train\n",
    "    train_acc /= n_train\n",
    "    val_loss /= n_val\n",
    "    val_acc /= n_val\n",
    "    \n",
    "    if val_acc > CURRENT_ACC:\n",
    "        print('epoch:', EPOCH, ', pass acc:', CURRENT_ACC, ', current acc:', val_acc)\n",
    "        CURRENT_ACC = val_acc\n",
    "        CURRENT_CHECKPOINT = 0\n",
    "        saver.save(sess, os.getcwd() + \"/model/acl/model-rnn-vector.ckpt\")\n",
    "    else:\n",
    "        CURRENT_CHECKPOINT += 1\n",
    "    EPOCH += 1\n",
    "    print('time taken:', time.time()-lasttime)\n",
    "    print('epoch:', EPOCH, ', training loss:', train_loss, ', training acc:', train_acc, ', valid loss:', val_loss, ', valid acc:', val_acc)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Evaluation on Testing dataset"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "saver = tf.train.import_meta_graph(\"model/acl/model-rnn-vector.ckpt.meta\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "INFO:tensorflow:Restoring parameters from model/acl/model-rnn-vector.ckpt\n",
      "Test: 0.8994\n"
     ]
    }
   ],
   "source": [
    "test_acc = 0\n",
    "all_predictions = []\n",
    "x_raw = []\n",
    "y_raw = []\n",
    "with tf.Session() as sess:\n",
    "    saver.restore(sess, \"model/acl/model-rnn-vector.ckpt\")\n",
    "    for b in range(n_test):\n",
    "        batch_x = test_data.iloc[test_groups_indices[b+1]].tokens.apply(lambda d: \n",
    "                                                                          generate_embeds_with_pads(d, test_groups_maxes[b+1]) ).values.tolist()\n",
    "        batch_y = test_data.loc[test_groups_indices[b+1]].bin_emotions.values.tolist()\n",
    "        \n",
    "        ### store these batches\n",
    "        x_raw = x_raw +[x for x in batch_x]\n",
    "        y_raw = y_raw + [y for y in batch_y]\n",
    "        \n",
    "        predictions, acc = sess.run([model.logits, model.accuracy], feed_dict = {model.X : batch_x, model.Y : batch_y})\n",
    "        \n",
    "        all_predictions.append(predictions)\n",
    "        test_acc += acc\n",
    "    \n",
    "    test_acc /= n_test\n",
    "    print('Test: %.4f' % (test_acc))    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [],
   "source": [
    "final_predictions = []\n",
    "\n",
    "for p in all_predictions:\n",
    "    for sub_p in p:\n",
    "        #print(sub_p)\n",
    "        final_predictions.append(sub_p)\n",
    "        \n",
    "all_predictions = [np.argmax(p) for p in final_predictions]\n",
    "        \n",
    "correct_predictions = float(sum(all_predictions == np.argmax(y_raw, axis=1)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "23625.0"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "correct_predictions"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Default Classification report\n",
      "             precision    recall  f1-score   support\n",
      "\n",
      "      anger       0.91      0.87      0.89      3504\n",
      "       fear       0.90      0.84      0.87      2960\n",
      "        joy       0.91      0.93      0.92      9227\n",
      "       love       0.82      0.75      0.78      2366\n",
      "    sadness       0.92      0.95      0.93      7203\n",
      "   surprise       0.78      0.86      0.82      1008\n",
      "\n",
      "avg / total       0.90      0.90      0.90     26268\n",
      "\n",
      "\n",
      "Accuracy:\n",
      "0.8993832800365463\n",
      "Correct Predictions:  23625\n",
      "precision: 0.87\n",
      "recall: 0.87\n",
      "f1: 0.87\n",
      "\n",
      "confusion matrix\n",
      " [[3064  100   72    9  258    1]\n",
      " [ 104 2490   57    2  135  172]\n",
      " [  36   15 8619  365  131   61]\n",
      " [  29   10  503 1769   52    3]\n",
      " [ 152   83  123   18 6817   10]\n",
      " [   0   80   46    1   15  866]]\n",
      "(row=expected, col=predicted)\n"
     ]
    },
    {
     "data": {
      "image/png": "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\nhQOOmZnV4v9kykdfboLB2wAAAABJRU5ErkJggg==\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7fdb3b4d8e10>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# predictions\n",
    "predictions_human_readable = ((x_raw, all_predictions))\n",
    "# actual targets\n",
    "target_human_readable = ((x_raw,  np.argmax(y_raw, axis=1)))\n",
    "\n",
    "### {0: 'anger', 1: 'fear', 2: 'joy', 3: 'love', 4: 'sadness', 5: 'surprise'}\n",
    "num_emotion_dict = {i:c for i,c in enumerate(mlb.classes_)}\n",
    "\n",
    "# convert results into dataframe\n",
    "model_test_result = pd.DataFrame(predictions_human_readable[1],columns=[\"emotion\"])\n",
    "test = pd.DataFrame(target_human_readable[1], columns=[\"emotion\"])\n",
    "\n",
    "model_test_result.emotion = model_test_result.emotion.map(lambda x: num_emotion_dict[int(float(x))])\n",
    "test.emotion = test.emotion.map(lambda x: num_emotion_dict[int(x)])\n",
    "\n",
    "evaluator.evaluate_class(model_test_result.emotion, test.emotion );"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
